package auth.controller;

import auth.service.IUserService;
import auth.utils.JwtUtil;
import common.dto.userdto.UserToken;
import common.dto.userdto.ChangePassword;
import common.dto.userdto.LoginDTO;
import common.dto.userdto.PasswordDTO;
import common.dto.userdto.UserDTO;
import common.model.result.Result;
import common.model.result.ResultCodeEnum;
import common.model.user.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.UUID;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;

import static common.utils.RedisConstants.LOGIN_USER_KEY;
import static common.utils.RedisConstants.LOGIN_USER_TTL;

@RestController
@RequestMapping("/auth")
public class AuthController {
    @Autowired
    private IUserService userService;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private JwtUtil jwtUtil;
    
    private static final String CODE_PREFIX = "login:code:";
    private static final String CAPTCHA_PREFIX = "login:captcha:";
    private static final long CODE_EXPIRE_TIME = 5; // 验证码有效期5分钟

    // 发送手机验证码
    @PostMapping("/code")
    public Result sendCode(@RequestParam String phone) {
        // 1.生成验证码
        String code = String.format("%06d", new Random().nextInt(1000000));
        
        // 2.保存验证码到Redis
        stringRedisTemplate.opsForValue().set(CODE_PREFIX + phone, code, CODE_EXPIRE_TIME, TimeUnit.MINUTES);
        
        // 3.模拟发送短信
        System.out.println("向手机号" + phone + "发送验证码：" + code);
        
        return Result.success("验证码发送成功");
    }

    // 获取简单验证码（用于密码登录）
    @GetMapping("/captcha")
    public Result getCaptcha() {
        try {
            System.out.println("开始生成验证码...");
            
            // 1.生成随机验证码
            String captchaText = generateCaptchaText(4); // 4位验证码
            System.out.println("生成的验证码文本: " + captchaText);
            
            // 2.将验证码存入Redis，设置过期时间为5分钟
            String captchaKey = UUID.randomUUID().toString();
            stringRedisTemplate.opsForValue().set(
                CAPTCHA_PREFIX + captchaKey, 
                captchaText, 
                5, 
                TimeUnit.MINUTES
            );
            
            // 3.返回验证码文本和key
            Map<String, String> result = new HashMap<>();
            result.put("captchaKey", captchaKey);
            result.put("captchaText", captchaText);
            
            return Result.success(result);
        } catch (Exception e) {
            System.err.println("生成验证码过程中发生异常: " + e.getMessage());
            e.printStackTrace();
            return Result.failure(ResultCodeEnum.FAIL, "生成验证码失败");
        }
    }
    
    /**
     * 生成随机验证码文本
     * @param length 验证码长度
     * @return 验证码文本
     */
    private String generateCaptchaText(int length) {
        String chars = "ABCDEFGHJKMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz23456789";
        StringBuilder sb = new StringBuilder();
        Random random = new Random();
        
        for (int i = 0; i < length; i++) {
            sb.append(chars.charAt(random.nextInt(chars.length())));
        }
        
        return sb.toString();
    }

    // 手机验证码登录
    @PostMapping("/login")
    public Result login(@RequestBody LoginDTO data, HttpServletResponse response) {
        if (data == null) {
            return Result.failure(ResultCodeEnum.FAIL, "请求数据格式错误");
        }
        
        // 1.1.验证码校验
        String cacheCode = stringRedisTemplate.opsForValue().get(CODE_PREFIX + data.getPhone());
        System.out.println("cacheCode~" + cacheCode + "phone~" + data.getPhone());
        if (cacheCode == null || !cacheCode.equals(data.getCode())) {
            return Result.failure(ResultCodeEnum.FAIL, "验证码错误或已过期");
        }
        //1.2.删除验证码
        stringRedisTemplate.delete(CODE_PREFIX + data.getPhone());
        // 2.查询用户
        User dbUser = userService.findByPhone(data.getPhone());
        UserToken userToken = new UserToken();
        
        // 3.如果用户不存在则自动注册
        if (dbUser == null) {
            dbUser = new User();
            dbUser.setTelephone(data.getPhone());
            userService.createUser(dbUser);
            dbUser = userService.findByPhone(data.getPhone()); // 重新查询获取ID
        }
        
        // 4.设置userDTO属性
        userToken.setId(dbUser.getId());  // 使用数据库查询出来的用户ID
        userToken.setNickName(dbUser.getNickName());
        userToken.setIcon(dbUser.getIcon());
        userToken.setUpdateTime(System.currentTimeMillis());
        userToken.setEmail(dbUser.getEmail());
        // 4.1.生成Access Token
        Map<String, Object> claims = new HashMap<>();
        claims.put("id", dbUser.getId());
        claims.put("nickName", dbUser.getNickName());
        String accessToken = jwtUtil.genToken(claims);
        userToken.setAccessToken(accessToken);
        userToken.setExpires_in(LOGIN_USER_TTL * 60); // 设置过期时间（秒）
        
        // 4.2.生成Refresh Token
        String refreshToken = UUID.randomUUID().toString();
        
        // 4.3.将Refresh Token存入Redis
        String refreshTokenKey = LOGIN_USER_KEY + refreshToken;
        stringRedisTemplate.opsForValue().set(refreshTokenKey, dbUser.getTelephone(), LOGIN_USER_TTL * 2, TimeUnit.MINUTES);
        
        // 4.4.将Refresh Token存储到HttpOnly cookie中
        Cookie cookie = new Cookie("user_refresh_token", refreshToken);
        cookie.setHttpOnly(true);
        cookie.setPath("/");
//        cookie.setDomain("test.jiang.com"); // 设置与Ingress匹配的域名
        cookie.setMaxAge(7 * 24 * 60 * 60); // 7天(秒)
        // 添加SameSite属性（Java可能需要自定义方法设置）
        response.addHeader("Set-Cookie", "SameSite=None");
        response.addCookie(cookie);
        
        // 6.返回用户信息
        return Result.success(userToken);
    }

    //手机号密码登录
    @PostMapping("/password/login")
    public Result passwordLogin(@RequestBody PasswordDTO data, HttpServletResponse response) {
        try {
            if (data == null) {
                return Result.failure(ResultCodeEnum.FAIL, "请求数据格式错误");
            }
            
            // 参数校验
            if (data.getPhone() == null || data.getPhone().isEmpty()) {
                return Result.failure(ResultCodeEnum.FAIL, "手机号不能为空");
            }
            
            if (data.getPassword() == null || data.getPassword().isEmpty()) {
                return Result.failure(ResultCodeEnum.FAIL, "密码不能为空");
            }
            
            //查询用户
            User dbUser = userService.findByPhone(data.getPhone());
            if (dbUser == null) {
                return Result.failure(ResultCodeEnum.FAIL, "用户不存在");
            }
            
            // 验证密码 - 使用加密验证
            if (!userService.verifyPassword(data.getPassword(), dbUser.getPassword())) {
                return Result.failure(ResultCodeEnum.FAIL, "密码错误");
            }
            
            // 创建UserToken对象
            UserToken userToken = new UserToken();
            
            // 设置userToken属性
            userToken.setId(dbUser.getId());
            userToken.setNickName(dbUser.getNickName());
            userToken.setIcon(dbUser.getIcon());
            userToken.setUpdateTime(System.currentTimeMillis());
            userToken.setEmail(dbUser.getEmail());
            
            // 生成Access Token
            Map<String, Object> claims = new HashMap<>();
            claims.put("id", dbUser.getId());
            claims.put("nickName", dbUser.getNickName());
            String accessToken = jwtUtil.genToken(claims);
            userToken.setAccessToken(accessToken);
            userToken.setExpires_in(LOGIN_USER_TTL * 60); // 设置过期时间（秒）
            
            // 生成Refresh Token
            String refreshToken = UUID.randomUUID().toString();
            
            // 将Refresh Token存入Redis
            String refreshTokenKey = LOGIN_USER_KEY + refreshToken;
            stringRedisTemplate.opsForValue().set(refreshTokenKey, dbUser.getTelephone(), LOGIN_USER_TTL * 2, TimeUnit.MINUTES);
            
            // 将Refresh Token存储到HttpOnly cookie中
            Cookie cookie = new Cookie("refreshToken", refreshToken);
            cookie.setHttpOnly(true);
            cookie.setPath("/");
//            cookie.setDomain("test.jiang.com"); // 设置与Ingress匹配的域名
            cookie.setMaxAge(7 * 24 * 60 * 60);
            // 添加SameSite属性（Java可能需要自定义方法设置）
            response.addHeader("Set-Cookie", "SameSite=None");
            response.addCookie(cookie);
            
            // 返回用户信息
            return Result.success(userToken);
        } catch (Exception e) {
            System.err.println("密码登录过程中发生异常: " + e.getMessage());
            e.printStackTrace();
            return Result.failure(ResultCodeEnum.FAIL, "登录失败");
        }
    }

    //修改密码
    @PostMapping("/update/password")
    public Result updatePassword(@RequestBody ChangePassword data) {
        try {
            System.out.println("修改密码请求: 手机号=" + (data != null ? data.getPhone() : "null") + 
                ", 验证码=" + data.getCode() + ", 密码长度=" + (data != null && data.getPassword() != null ? data.getPassword().length() : 0));
            
            // 参数校验
            if (data == null || data.getPhone() == null || data.getPhone().isEmpty()) {
                return Result.failure(ResultCodeEnum.FAIL, "手机号不能为空");
            }
            
            if (data.getPassword() == null || data.getPassword().isEmpty()) {
                return Result.failure(ResultCodeEnum.FAIL, "新密码不能为空");
            }
            
            if (data.getCode() == null || data.getCode().isEmpty()) {
                return Result.failure(ResultCodeEnum.FAIL, "验证码不能为空");
            }
            
            // 验证码校验
            String cacheCode = null;
            try {
                cacheCode = stringRedisTemplate.opsForValue().get(CODE_PREFIX + data.getPhone());
                System.out.println("从Redis获取的验证码: " + cacheCode);
            } catch (Exception e) {
                System.err.println("从Redis获取验证码时出错: " + e.getMessage());
                e.printStackTrace();
                return Result.failure(ResultCodeEnum.FAIL, "验证码校验失败，请重试");
            }
            
            if (cacheCode == null || !cacheCode.equals(data.getCode())) {
                return Result.failure(ResultCodeEnum.FAIL, "验证码错误或已过期");
            }
            
            // 删除验证码
            try {
                stringRedisTemplate.delete(CODE_PREFIX + data.getPhone());
            } catch (Exception e) {
                System.err.println("删除Redis验证码时出错: " + e.getMessage());
                // 继续流程，不阻止修改密码
            }
            
            // 检查用户是否存在
            User existingUser = userService.findByPhone(data.getPhone());
            if (existingUser == null) {
                return Result.failure(ResultCodeEnum.FAIL, "用户不存在");
            }
            
            // 更新密码
            try {
                userService.updatePassword(data.getPassword(), data.getPhone());
                System.out.println("密码修改成功: " + data.getPhone());
                return Result.success("密码修改成功");
            } catch (Exception e) {
                System.err.println("更新密码时出错: " + e.getMessage());
                e.printStackTrace();
                return Result.failure(ResultCodeEnum.FAIL, "修改密码失败: " + e.getMessage());
            }
        } catch (Exception e) {
            System.err.println("修改密码过程中发生异常:");
            e.printStackTrace();
            return Result.failure(ResultCodeEnum.FAIL, "修改密码失败: " + e.getMessage());
        }
    }

    //更新用户信息
    @PostMapping("/update")
    public Result update(@RequestBody UserDTO userDTO) {
        //更新用户信息
        return userService.updateUser(userDTO);
    }

    //退出登录
    @RequestMapping("/logout")
    public Result logout(
            @RequestHeader(value = "Authorization", required = false) String accessToken,
            HttpServletRequest  request,
            HttpServletResponse  response
            ) {
        String refreshToken = null;
        System.out.println("退出登录方法被调用");
        System.out.println("accessToken=" + accessToken);
        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                if ("user_refresh_token".equals(cookie.getName())) {
                    refreshToken = cookie.getValue();
                }
            }
        }
        System.out.println("refreshToken=" + refreshToken);
        if (refreshToken == null || accessToken == null) {
            return Result.failure(ResultCodeEnum.FAIL, "refreshToken或accessToken为空！");
        }
        
        // 1.删除redis中的refreshToken
        String refreshTokenKey = LOGIN_USER_KEY + refreshToken;
        stringRedisTemplate.delete(refreshTokenKey);
        System.out.println("删除Redis中的refreshToken：" + refreshTokenKey);
        
        // 2.将accessToken加入黑名单
        String blacklistKey = "token:blacklist";
        stringRedisTemplate.opsForSet().add(blacklistKey, accessToken);
        // 设置黑名单的过期时间，与accessToken的过期时间一致
        stringRedisTemplate.expire(blacklistKey, LOGIN_USER_TTL, TimeUnit.MINUTES);
        System.out.println("将accessToken加入黑名单：" + accessToken);
        
        // 3. 清除refreshToken cookie
        Cookie cookie = new Cookie("refreshToken", null); // 值设为null或者空字符串
        cookie.setHttpOnly(true);
        cookie.setSecure(false); // 与设置时保持一致，如果不使用HTTPS，设为false
        cookie.setPath("/"); // 路径与设置时一致
        cookie.setDomain("test.jiang.com"); // 设置与创建时相同的域名
        cookie.setMaxAge(0); // 设置maxAge为0，立即过期
        response.addCookie(cookie);
        System.out.println("清除refreshToken cookie");
        
        // 同时清除响应头中的refreshToken
        response.setHeader("refreshToken", "");
        
        return Result.success("登出成功");
    }
    //刷新token
    @RequestMapping("/refresh-token")
    public Result refreshToken(
            @CookieValue(value = "refreshToken", required = false) String refreshToken,
            HttpServletResponse response,
            HttpServletRequest request) {
        
        System.out.println("刷新token方法被调用");
        System.out.println("从Cookie中获取的refreshToken=" + refreshToken);
        
        // 打印所有Cookie信息
        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            System.out.println("请求中的所有Cookie:");
            for (Cookie c : cookies) {
                System.out.println("Cookie名称: " + c.getName() + ", 值: " + c.getValue());
            }
        } else {
            System.out.println("请求中没有Cookie");
        }
        
        // 打印所有请求头
        System.out.println("请求中的所有Header:");
        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String headerName = headerNames.nextElement();
            System.out.println("Header名称: " + headerName + ", 值: " + request.getHeader(headerName));
        }

        if (refreshToken == null) {
            System.out.println("refreshToken为空，返回错误");
            return Result.failure(ResultCodeEnum.FAIL, "refreshToken为空！");
        }
        
        // 1.从Redis中获取原版refreshToken
        String refreshTokenKey = LOGIN_USER_KEY + refreshToken;
        String telephone = stringRedisTemplate.opsForValue().get(refreshTokenKey);
        System.out.println("从Redis中获取的电话号码：" + telephone);
        
        // 2.验证refreshToken
        if (telephone == null) {
            System.out.println("token验证失败，Redis中没有找到对应的电话号码");
            return Result.failure(ResultCodeEnum.FAIL, "token验证失败");
        }
        
        // 3.删除Redis中的refreshToken
        stringRedisTemplate.delete(refreshTokenKey);
        System.out.println("已删除旧的refreshToken：" + refreshTokenKey);
        
        // 4.生成新的refreshToken
        String newRefreshToken = UUID.randomUUID().toString();
        System.out.println("生成新的refreshToken：" + newRefreshToken);
        
        // 5.将新的refreshToken存入Redis
        String newRefreshTokenKey = LOGIN_USER_KEY + newRefreshToken;
        stringRedisTemplate.opsForValue().set(newRefreshTokenKey, telephone, LOGIN_USER_TTL * 2, TimeUnit.MINUTES);
        System.out.println("新的refreshToken已存入Redis：" + newRefreshTokenKey);
        
        // 6.将新的refreshToken存入cookie
        Cookie cookie = new Cookie("refreshToken", newRefreshToken);
        cookie.setHttpOnly(true);
        cookie.setSecure(true);
        cookie.setPath("/");
        cookie.setDomain("test.jiang.com");
        cookie.setMaxAge((int) (LOGIN_USER_TTL * 2 * 60));
        response.addHeader("Set-Cookie", "SameSite=None");
        response.addCookie(cookie);
        System.out.println("新的refreshToken已存入cookie，过期时间：" + (LOGIN_USER_TTL * 2 * 60) + "秒");
        
        // 同时在响应头中返回refreshToken
        response.setHeader("refreshToken", newRefreshToken);
        System.out.println("新的refreshToken已添加到响应头");
        
        // 7.生成新的Access Token
        User dbUser = userService.findByPhone(telephone);
        System.out.println("根据电话号码找到用户：" + (dbUser != null ? dbUser.getId() : "null"));
        
        Map<String, Object> claims = new HashMap<>();
        claims.put("id", dbUser.getId());
        claims.put("nickName", dbUser.getNickName());
        String newAccessToken = jwtUtil.genToken(claims);
        System.out.println("生成新的accessToken：" + newAccessToken);
        
        // 8.设置userToken属性
        UserToken userToken = new UserToken();
        userToken.setAccessToken(newAccessToken);
        userToken.setExpires_in(LOGIN_USER_TTL * 60); // 设置过期时间（秒）
        userToken.setRefreshToken(newRefreshToken); // 在返回的数据中也包含refreshToken
        
        // 9.返回用户信息
        System.out.println("刷新token成功，返回新的token信息");
        return Result.success(userToken);
    }

    //用户仪表盘
    @GetMapping("/dashboard")
    public Result getUserDashboard(@RequestHeader(value = "uid") Long uid){
        return userService.getUserDashboard(uid);
    }

    //根据id获取用户信息
    @GetMapping("/detail")
    public Result getUserById(@RequestParam("id") Long id) {
        return userService.getUserDetail(id);
    }

    //后台

    //获取用户列表
    @GetMapping("/jiang/list")
    public Result getUserList() {
        return userService.getUserList();
    }

    //获取所有用户
    @GetMapping("/jiang/listForCart")
    public Result getUserListForCart() {
        return userService.getUserListForCart();
    }

    //根据id获取用户详情
    @GetMapping("/jiang/detail/{id}")
    public Result getUserDetail(@PathVariable Long id) {
        return userService.getUserDetail(id);
    }

    //更新用户信息
    @PostMapping("/jiang/update")
    public Result updateUser(@RequestBody User user) {
        return userService.jiangUpdateUser(user);
    }

    //删除用户
    @PostMapping("/jiang/delete")
    public Result deleteUser(@RequestBody Long id) {
        return userService.jiangDeleteUser(id);
    }

    @GetMapping("/customer/search")
    public Result getCustomerSearch(@RequestParam("name") String name) {
        return userService.getOnlinAdminId();
    }
}
